package com.sfexpress.tools;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.sfexpress.tools.entity.ConsCheckResult;
import com.sfexpress.tools.entity.MysqlIndexInfo;
import com.sfexpress.tools.entity.MysqlTableInfo;
import com.sfexpress.tools.entity.ConsCheckResult.ItemResult;
import com.sfexpress.tools.entity.ConsCheckResult.ConflictItem;
import com.sfexpress.tools.utils.Pair;
import com.sfexpress.tools.utils.SetUtil;

public class MysqlIndexInfoChecker extends AbstractChecker {
	
	public void checkConsistency(MysqlTableInfo pvTableInfo, MysqlTableInfo gvTableInfo, ConsCheckResult result) {
		
		logger.info("开始执行表索引一致性校验 ...");
		
		Map<String, MysqlIndexInfo> pvIndexInfoMap = getIndexInfoMap(pvTableInfo.getIndexInfoList());
		Map<String, MysqlIndexInfo> gvIndexInfoMap = getIndexInfoMap(gvTableInfo.getIndexInfoList());
		
		Set<String> pvIndexInfoSet = pvIndexInfoMap.keySet();
		Set<String> gvIndexInfoSet = gvIndexInfoMap.keySet();
		
		Set<String> newItems = SetUtil.getDiffSet(gvIndexInfoSet, pvIndexInfoSet);
		Set<String> deletedItems = SetUtil.getDiffSet(pvIndexInfoSet, gvIndexInfoSet);
		
		if(newItems.size() > 0) {
			logger.warn("检测到灰度版本表存在新索引 : " + Arrays.toString(newItems.toArray()));
			// 信息保留
			result.getIdxInfoCheckResult().setCoincident(false);
			for(String newItem : newItems) {
				result.getIdxInfoCheckResult().getNewItems().add(gvIndexInfoMap.get(newItem));
			}
		}
		
		if(deletedItems.size() > 0) {
			logger.warn("检测到灰度版本没有的索引 : " + Arrays.toString(deletedItems.toArray()));
			result.getIdxInfoCheckResult().setCoincident(false);
			for(String deletedItem : deletedItems) {
				result.getIdxInfoCheckResult().getDeletedItems().add(pvIndexInfoMap.get(deletedItem));
			}
		}
		
		Set<String> commItems = SetUtil.getInterSet(pvIndexInfoSet, gvIndexInfoSet);
		for(String item : commItems) {
			MysqlIndexInfo pvItem = pvIndexInfoMap.get(item);
			MysqlIndexInfo gvItem = gvIndexInfoMap.get(item);
			if(!checkConsistency(pvItem, gvItem, result)) {
//				result.setCoincident(false);
				logger.warn("检测到有不一致的索引 : " );
				logger.warn("From 生产版本库 : " + pvItem);
				logger.warn("From 灰度版本库 : " + gvItem);
				result.getIdxInfoCheckResult().setCoincident(false);
				result.getIdxInfoCheckResult().getConflictItems().add(new Pair<MysqlIndexInfo, MysqlIndexInfo>(pvItem, gvItem));
			}
		}
		
		logger.info("表索引一致性校验结束!");
		
	}
	
	private boolean checkConsistency(MysqlIndexInfo pvIndexInfo, MysqlIndexInfo gvIndexInfo, ConsCheckResult result) {
		
		boolean flag = true;
		String key = pvIndexInfo.getIndexName() + "$" + pvIndexInfo.getColumnName();
		ItemResult<MysqlIndexInfo> idxInfoCheckResult = result.getIdxInfoCheckResult();
		if(pvIndexInfo.getNonUnique() != gvIndexInfo.getNonUnique()) {
			flag = false;
			idxInfoCheckResult.addConflictItem(key, new ConflictItem(key, "NON_UNIQUE", String.valueOf(pvIndexInfo.getNonUnique()), String.valueOf(gvIndexInfo.getNonUnique())));
		}
//		if(!StringUtils.equals(pvIndexInfo.getIndexSchema(), gvIndexInfo.getIndexSchema())) {
//			return false;
//		}
//		if(!StringUtils.equals(pvIndexInfo.getIndexName(), gvIndexInfo.getIndexName())) {
//			return false;
//		}
//		if(!StringUtils.equals(pvIndexInfo.getColumnName(), gvIndexInfo.getColumnName())) {
//			return false;
//		}
		if(!StringUtils.equals(pvIndexInfo.getCollation(), gvIndexInfo.getCollation())) {
			flag = false;
			idxInfoCheckResult.addConflictItem(key, new ConflictItem(key, "COLLATION", pvIndexInfo.getCollation(), gvIndexInfo.getCollation()));
		}
		if(!StringUtils.equals(pvIndexInfo.getNullable(), gvIndexInfo.getNullable())) {
			flag = false;
			idxInfoCheckResult.addConflictItem(key, new ConflictItem(key, "NULLABLE", pvIndexInfo.getNullable(), gvIndexInfo.getNullable()));
		}
		if(!StringUtils.equals(pvIndexInfo.getIndexType(), gvIndexInfo.getIndexType())) {
			flag = false;
			idxInfoCheckResult.addConflictItem(key, new ConflictItem(key, "INDEX_TYPE", pvIndexInfo.getIndexType(), gvIndexInfo.getIndexType()));
		}
		return flag;
	}
	
	private Map<String, MysqlIndexInfo> getIndexInfoMap(List<MysqlIndexInfo> mysqlIndexInfoList) {
		
		return Maps.uniqueIndex(mysqlIndexInfoList, new Function<MysqlIndexInfo, String>() {

			@Override
			public String apply(MysqlIndexInfo input) {
				return input.getIndexName() + "$" + input.getColumnName();
			}
		});
		
	}

}
